package top.codef.secure.config.delegates;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import com.fasterxml.jackson.databind.ObjectMapper;

import top.codef.secure.config.interfaces.CerberusCustomLoginCustomer;
import top.codef.secure.config.interfaces.CerberusHttpSecurityConfig;
import top.codef.secure.config.interfaces.LoginFailedDecorator;
import top.codef.secure.config.interfaces.LoginSuccessDecorator;
import top.codef.secure.handlers.CerberusLoginFailedHandler;
import top.codef.secure.handlers.CerberusLoginSuccessHandler;
import top.codef.secure.login.CerberusAuthenticationProvider;
import top.codef.secure.login.CerberusCustomAuthenticationConfigure;
import top.codef.secure.login.interfaces.CerberusAuthenticationChecker;
import top.codef.secure.login.interfaces.CerberusUserDetailsService;
import top.codef.secure.properties.CerberusCsrfProperties;
import top.codef.secure.properties.CerberusCustomLoginProperties;
import top.codef.secure.properties.CerberusLoginReturnProperties;

@Configuration
@EnableConfigurationProperties({ CerberusCustomLoginProperties.class, CerberusLoginReturnProperties.class })
@ConditionalOnProperty(value = "cerberus.secure.custom-login.enabled", havingValue = "true")
@Order(6)
@AutoConfigureBefore(UserDetailsServiceAutoConfiguration.class)
public class CerberusCustomLoginConfig implements CerberusHttpSecurityConfig {

	@Autowired
	private CerberusCustomLoginProperties cerberusCustomLoginProperties;

	@Autowired
	private CerberusLoginReturnProperties cerberusLoginReturnProperties;

	@Autowired(required = false)
	private List<CerberusAuthenticationChecker> checkers;

	@Autowired
	private List<CerberusUserDetailsService> userDetailsServices;

	@Autowired(required = false)
	private CerberusCustomLoginCustomer cerberusCustomLoginCustomer;

	@Autowired
	private ObjectMapper objectMapper;

	@Autowired(required = false)
	private CerberusCsrfProperties cerberusCsrfProperties;

	@Autowired
	private LoginSuccessDecorator loginSuccessDecorator;

	@Autowired
	private LoginFailedDecorator loginFailedDecorator;

	private final Log logger = LogFactory.getLog(CerberusCustomLoginConfig.class);

	@Override
	public void secure(HttpSecurity httpSecurity) throws Exception {
		logger.debug("自定义登录设置");
		@SuppressWarnings("removal")
		CerberusCustomAuthenticationConfigure cerberusCustomAuthenticationConfigure = httpSecurity
				.apply(new CerberusCustomAuthenticationConfigure(cerberusCustomLoginProperties))
				.loginProcessingUrl(cerberusCustomLoginProperties.getLoginPath());
		if (cerberusCustomLoginProperties.isRestful()) {
			CerberusLoginSuccessHandler loginSuccessHandler = new CerberusLoginSuccessHandler(objectMapper,
					cerberusCsrfProperties, cerberusLoginReturnProperties, loginSuccessDecorator);
			CerberusLoginFailedHandler loginFailHandler = new CerberusLoginFailedHandler(objectMapper,
					cerberusLoginReturnProperties, loginFailedDecorator);
			cerberusCustomAuthenticationConfigure.successHandler(loginSuccessHandler).failureHandler(loginFailHandler);
		}
		if (cerberusCustomLoginCustomer != null)
			cerberusCustomLoginCustomer.custom(cerberusCustomAuthenticationConfigure);
		AuthenticationManagerBuilder authenticationManagerBuilder = httpSecurity
				.getSharedObject(AuthenticationManagerBuilder.class);
		authenticationManagerBuilder.authenticationProvider(cerberusAuthenticationProvider());
	}

	@Bean
	public CerberusAuthenticationProvider cerberusAuthenticationProvider() {
		CerberusAuthenticationProvider cerberusAuthenticationProvider = new CerberusAuthenticationProvider(checkers,
				userDetailsServices, cerberusCustomLoginProperties);
		return cerberusAuthenticationProvider;
	}
}
